﻿using Microsoft.WindowsAzure.Storage.Table.DataServices;
using System;
using System.Collections.Generic;
using System.Data.Services.Common;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.ServiceRuntime;
using System.Reflection;
using Microsoft.WindowsAzure.Storage.Table;
using System.IO;
using System.Xml.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Data;

namespace POC.Loggers.Model
{

    [Serializable()]
    public class LogEntry : TableEntity
    {
        // By default, when creating a new entity, the PartitionKey is set to the current year, and the RowKey is a GUID. Insert the ticks in the beginning of RowKey because the result returned by a query is ordered by PartitionKey and then RowKey.
        public LogEntry()
        {
            this.Fill();
        }

        public LogEntry(string message, string category)
        {
            this.Fill();
            this.Message = message;
            this.Category = category;
        }

        public LogEntry(string source, TraceEventType eventType, int id, TraceEventCache eventCache, TraceOptions options, string message)
        {
            this.Fill();
            this.Message = message;
            this.Category = eventType.ToString();
            this.LogSource = source;
            this.EventID = id;
            this.EventType = (int)eventType; // INFO
            this.StackTrace = eventCache.Callstack;
            this.ThreadId = eventCache.ThreadId;
            this.ProcessId = eventCache.ProcessId;

            this.traceEventType = eventType;
            this.eventCache = eventCache;
            this.traceOutputOptions = options;

            this.Timestamp = (eventCache != null) ? eventCache.DateTime : DateTime.UtcNow;
        }



        public long LogID { get; set; }

        public string Category { get; set; }

        public short CategoryNumber { get; set; }

        public int EventType { get; set; }

        public int EventID { get; set; }

        public string Data { get; set; }

        public string Tags;

        public string InstanceID { get; set; }

        public string DeploymentID { get; set; }

        public string MachineName { get; set; }

        public int ProcessId { get; set; }

        public string ThreadId { get; set; }

        public string LogSource { get; set; }

        public string UserName { get; set; }

        public string Message { get; set; }

        public string StackTrace { get; set; }

        public long ErrorCode { get; set; }

        public System.DateTime TimeGenerated { get; set; }

        public System.DateTime TimeWritten { get; set; }

        public System.Guid CoRelationGuid { get; set; }


        [NonSerialized()]
        [XmlIgnore]
        internal TraceOptions traceOutputOptions;

        [NonSerialized()]
        [XmlIgnore]
        internal TraceEventCache eventCache;

        // ??
        [NonSerialized()]
        [XmlIgnore]
        internal TraceEventType traceEventType;

    }

    public static class LogEntryExtn
    {
       public static LogEntry Fill(this LogEntry entry)
        {
            entry.PartitionKey = DateTime.Now.ToString("MM_yyyy");
            entry.RowKey = string.Format("{0:16}|{1}",DateTime.Now.Ticks, Guid.NewGuid());
            entry.Category = TraceEventType.Information.ToString();
            entry.CategoryNumber = CategoryType.Application;
            entry.ErrorCode = -1;
            entry.EventID = -1;
            entry.InstanceID = AzureLoggingSettings.AzureInstanceID;
            entry.DeploymentID = AzureLoggingSettings.AzureDeploymentID;
            entry.CoRelationGuid = Guid.NewGuid();
            entry.LogID = DateTime.Now.Ticks - 9999999;
            entry.EventType = (int)TraceEventType.Information;
            entry.MachineName = Environment.MachineName;
            entry.Message = "Log Created";
            entry.TimeGenerated = DateTime.Now;
            entry.TimeWritten = DateTime.Now;
            //entry.Timestamp = DateTime.UtcNow;
            entry.UserName = Environment.UserName;
            entry.LogSource = Assembly.GetExecutingAssembly().Location;
            return entry;
        }
    }

    public static class ClogDataClassesDataContextExtn
    {       

        #region Serializable
        public static byte[] ToByteArray(this LogEntry message)
        {
            using (MemoryStream stream = new MemoryStream())
            {
                BinaryFormatter formatter = new BinaryFormatter();
                formatter.Serialize(stream, message);
                return stream.ToArray();
            }
        }
     

        /*
         * private static DataColumn CreateDataColumn(string columnName, object defaultObject)
        {
            DataColumn cl = new DataColumn(columnName , defaultObject.GetType());
            return cl;
        }
        public static DataTable ToTable(this LogEntry message)
        {
            DataTable dt = new DataTable("LogEntry");

            dt.Columns.Add( CreateDataColumn("Category",           message.Category));
            dt.Columns.Add(CreateDataColumn("CategoryNumber", message.CategoryNumber));
            dt.Columns.Add(CreateDataColumn("CoRelationGuid", message.CoRelationGuid.ToString()));
            dt.Columns.Add(CreateDataColumn("Data", message.Data));
            dt.Columns.Add(CreateDataColumn("DeploymentID", message.DeploymentID));
            dt.Columns.Add(CreateDataColumn("ErrorCode", message.ErrorCode));
            dt.Columns.Add(CreateDataColumn("ETag", message.ETag));
            dt.Columns.Add(CreateDataColumn("eventCache", message.eventCache.ToString()));
            dt.Columns.Add(CreateDataColumn("EventID", message.EventID));
            dt.Columns.Add(CreateDataColumn("EventType", message.EventType));
            dt.Columns.Add(CreateDataColumn("InstanceID", message.InstanceID));
            dt.Columns.Add(CreateDataColumn("LogID", message.LogID));
            dt.Columns.Add(CreateDataColumn("LogSource", message.LogSource));
            dt.Columns.Add(CreateDataColumn("MachineName", message.MachineName));
            dt.Columns.Add(CreateDataColumn("Message", message.Message));
            dt.Columns.Add(CreateDataColumn("PartitionKey", message.PartitionKey));
            dt.Columns.Add(CreateDataColumn("ProcessId", message.ProcessId));
            dt.Columns.Add(CreateDataColumn("RowKey", message.RowKey));
            dt.Columns.Add(CreateDataColumn("Tags", message.Tags));
            dt.Columns.Add(CreateDataColumn("ThreadId", message.ThreadId));
            dt.Columns.Add(CreateDataColumn("TimeGenerated", message.TimeGenerated));
            dt.Columns.Add(CreateDataColumn("Timestamp", message.Timestamp));
            dt.Columns.Add(CreateDataColumn("TimeWritten", message.TimeWritten));
            
            return dt;
        }
         * */
        public static string ToString(this LogEntry message, string delimiter="\t")
        {
            string[] allProperties = new string[] { 
            message.Category, 
            message.CategoryNumber.ToString(), 
            message.CoRelationGuid.ToString(), 
            message.Data, 
            message.DeploymentID, 
            message.ErrorCode.ToString(),
            message.ETag, 
            message.eventCache == null ? string.Empty:  message.eventCache.ToString(),
            message.EventID.ToString(),
            message.EventType.ToString(), 
            message.InstanceID, 
            message.LogID.ToString(),
            message.LogSource, 
            message.MachineName, 
            message.Message, 
            message.PartitionKey, 
            message.ProcessId.ToString(), 
            message.RowKey, 
            message.Tags,
            message.ThreadId, 
            message.TimeGenerated.ToString(), 
            message.Timestamp.ToString(), 
            message.TimeWritten.ToString()
            };
            return string.Join(delimiter, allProperties);
        }
        public static string ToXml(this LogEntry message)
        {
            using (MemoryStream stream = new MemoryStream())
            {
                XmlSerializer formatter = new XmlSerializer(typeof(LogEntry), new Type[]{ typeof(TableEntity) });
                    formatter.Serialize(stream, message);
                    return UTF8Encoding.UTF8.GetString(stream.ToArray());
            }
        }
       
        public static LogEntry FromXml(this string buffer)
        {
            using (MemoryStream stream = new MemoryStream(UTF8Encoding.UTF8.GetBytes(buffer)))
            {
                XmlSerializer formatter = new XmlSerializer(typeof(LogEntry), new Type[] { typeof(TableEntity) });
                object o = formatter.Deserialize(stream);
                return (LogEntry)o;
            }
        }
        public static LogEntry ToLogEntry(this byte[] buffer)
        {
            using (MemoryStream stream = new MemoryStream(buffer))
            {
                BinaryFormatter formatter = new BinaryFormatter();
                object o = formatter.Deserialize(stream);
                return (LogEntry)o;
            }
        }
        #endregion
    }
}
